package com.obelisco.modelo.dao.hibernate;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.ResourceBundle;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.criterion.Expression;
import org.hibernate.criterion.Order;
import org.hibernate.validator.ClassValidator;
import org.hibernate.validator.InvalidValue;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.obelisco.exception.ObeliscoException;
import com.obelisco.modelo.dao.ICarpetaTransaccionDAO;
import com.obelisco.modelo.data.CarpetaTransaccion;
import com.obelisco.modelo.data.DataGenerica;
import com.obelisco.modelo.data.Grupo;
import com.obelisco.modelo.data.Sistema;
import com.obelisco.modelo.data.Transaccion;
import com.obelisco.modelo.data.Usuario;

public class CarpetaTransaccionDAO extends HibernateDAO implements
		ICarpetaTransaccionDAO {

	public CarpetaTransaccion findByPK(Serializable clave) {
		try {
			CarpetaTransaccion data = (CarpetaTransaccion) getHibernateTemplate()
					.load(CarpetaTransaccion.class, clave);
			return data.getEstado().equals("B") ? null : data;
		} catch (RuntimeException re) {
			throw re;
		}
	} 

	public List loadAll() {
		try {

			List lista = getHibernateTemplate()
					.find(
							"from CarpetaTransaccion carpeta where carpeta.estado != 'B'");
			return lista;
		} catch (RuntimeException re) {
			throw re;
		}
	}

	public CarpetaTransaccion findTree(Sistema sistema) {

		final Sistema aSistema = sistema;

		List lista = getHibernateTemplate().executeFind(
				new HibernateCallback() {

					private void recorrer(CarpetaTransaccion carpeta) {

//						for (Iterator i = carpeta.getHijos().values()
//								.iterator(); i.hasNext();) {
						for (Iterator i = carpeta.getHijos()
						.iterator(); i.hasNext();) {
						
							CarpetaTransaccion c = (CarpetaTransaccion) i
									.next();

							if (c.getHijos().size() >= 0) {
								recorrer(c);
							}

							for (Iterator j = c.getTransacciones()
									.iterator(); j.hasNext();) {
								Transaccion t = (Transaccion) j.next();
							}

						}
					}

					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {

						session.enableFilter("activo");
						Criteria c = session
								.createCriteria(CarpetaTransaccion.class);

						c.add(Expression.eq("sistema", aSistema));
						c.add(Expression.eq("nivel", new Integer(0)));

						List lista = c.list();

						for (Iterator i = lista.iterator(); i.hasNext();) {
							CarpetaTransaccion carpetaRaiz = (CarpetaTransaccion) i
									.next();
							recorrer(carpetaRaiz);
						}

						return lista;

					}
				});

		CarpetaTransaccion carpetaRaiz = null;
		for (Iterator i = lista.iterator(); i.hasNext();) {
			carpetaRaiz = (CarpetaTransaccion) i.next();
		}

		return carpetaRaiz;
	}

	public void delete(CarpetaTransaccion objeto) {
		((CarpetaTransaccion) objeto).setEstado("B");
		getHibernateTemplate().saveOrUpdate(objeto);
	}

	ClassValidator carpetaTransaccionValidator = new ClassValidator(CarpetaTransaccion.class,ResourceBundle.getBundle("com.obelisco.modelo.data.hibernate-validator"));
	
	public void validate(CarpetaTransaccion objeto) {
		
		if (objeto.getPadre() != null) {
			CarpetaTransaccion padre = objeto.getPadre();
			objeto.setRuta(padre.getRuta() + objeto.getNombre() + " / ");
		}

		InvalidValue[] validationMessages =  carpetaTransaccionValidator.getInvalidValues(objeto);

		StringBuffer errores = new StringBuffer();
		for (int i = 0; i < validationMessages.length; i++) {
			InvalidValue value = validationMessages[i];
			errores.append(value.getPropertyName() + " - "+ value.getMessage() + "<br/>");
		}

		if (errores.length() > 0) {
			
			throw new ObeliscoException(errores.toString());
		}

	}

	public void save(CarpetaTransaccion objeto) {
		
		if (objeto.getPadre() != null) {
			CarpetaTransaccion padre = objeto.getPadre();
			objeto.setRuta(padre.getRuta() + objeto.getNombre() + " / ");
		}
		
		validate(objeto);
		getHibernateTemplate().saveOrUpdate(objeto);
	}

	public List findByProperty(String propertyName, Object value) {
		try {

			String queryString = "from CarpetaTransaccion modelo where modelo."
					+ propertyName + "= ?";
			return getHibernateTemplate().find(queryString, value);
		} catch (RuntimeException re) {
			// log.error("find by property name failed", re);
			throw re;
		}
	}

	private void recorrer(CarpetaTransaccion carpeta, Sistema sistema,
			Usuario usuario) {

		for (Iterator i = carpeta.getHijos().iterator(); i.hasNext();) {
			CarpetaTransaccion hijo = (CarpetaTransaccion) i.next();

			if (hijo.getHijos().size() >= 0) {

				recorrer(hijo, sistema, usuario);
				if (hijo.getTransacciones().size() == 0
						&& hijo.getHijos().size() == 0) {

					i.remove();

				}

			}

		}

		for (Iterator j = carpeta.getTransacciones().iterator(); j
				.hasNext();) {
			Transaccion t = (Transaccion) j.next();

			if (usuario.getGrupos().size() == 0) {
				j.remove();
			} 
			else {				
				boolean conPermiso = false;
				for (Grupo grupo : usuario.getGrupos()) {
					if (grupo.getId().getSistema().equals(sistema)) {
						for (Transaccion tg : grupo.getTransacciones()) {							
							if (tg.equals(t)) {
									conPermiso = true;
									break;								
							}
							
						}

					}

				}
				
				if (!conPermiso) {
					j.remove();
				}

			}

		}


	}

	public CarpetaTransaccion findTree(Sistema sistema, Usuario usuario) {
		// TODO Auto-generated method stub
		CarpetaTransaccion raiz = null;

		Session session = getSession();

		Criteria criteria = session.createCriteria(CarpetaTransaccion.class);
		criteria.add(Expression.eq("sistema", sistema));
		criteria.add(Expression.eq("nivel", new Integer(0)));
		//criteria.addOrder(Order.asc("orden"));

		List<CarpetaTransaccion> carpetas = criteria.list();

		for (CarpetaTransaccion carpeta : carpetas) {

			recorrer(carpeta, sistema, usuario);
			raiz = carpeta;

		}

		return raiz;
	}

}
